package com.hanxiaozhang.sourcecode.map;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author hanxinghua
 * @create 2020/6/2
 * @since 1.0.0
 */
public class Test {

    /**
     * 最大容量，如果某个具有参数的构造函数隐式指定了更高的值，则使用该值。
     * 必须是2的幂<=1<<30。
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 构造函数中未指定时，使用的负载因子
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    public static void main(String[] args) {

        // comparingByKey  comparingByValue() comparingByKey  comparingByValue getOrDefault
        // forEach  replaceAll putIfAbsent remove(Object key, Object value)
        // replace(K key, V oldValue, V newValue) replace(K key, V value)  computeIfAbsent
        // computeIfPresent  compute  merge

//        resizeTest();

//        putIfAbsentTest();

        computeSomeMethodTest();

//        binaryTest();

//        int tableSize = tableSizeFor(8);
//        System.out.println(tableSize);

    }

    private static void resizeTest() {
        Map<String, String> map = new MyHashMap<>();
        map.put("a1", "123");
        map.put("a2", "123");
        map.put("a3", "123");
        map.put("a4", "123");
        map.put("a5", "123");
        map.put("a6", "123");
        map.put("a7", "123");
        map.put("a8", "123");
        map.put("a9", "123");
        map.put("a10", "123");
        map.put("a11", "123");
        map.put("a12", "123");
        map.put("a13", "123");
        map.put("a14", "123");
        map.put("a15", "123");
        map.put("a16", "123");
        map.put("a17", "123");
    }


    private static void comparingTest(){


    }

    /**
     * putIfAbsent作用：
     * key不存在时，添加key-value映射对
     * key为null时，覆盖value值
     */
    public static void putIfAbsentTest() {

        Map<String, String> map = new MyHashMap<>();
        map.put("a1", "123");
        map.put("a2", null);
        map.putIfAbsent("a1", "a1");
        map.putIfAbsent("a2", "a2");
        map.putIfAbsent("a3", "a3");
        map.forEach((x, y) -> {
            System.out.println("key: " + x + ", value: " + y);
        });

    }

    /**
     * compute相关方法测试
     */
    private static void computeSomeMethodTest() {
        Map<String, Integer> map = new MyHashMap<>();
        map.put("aj1", 1000);
        map.put("aj2", 1500);
        map.put("aj6", null);
        map.put("aj7", null);

        // # compute的使用：
        // 使用一：aj1打9折
        Integer aj1 = map.compute("aj1", (key, value) -> value * 90 / 100);
        System.out.println("aj1打9折: " + aj1);

        // 使用二（证明）：如果在compute中传递的重映射函数返回null，则将映射从Map中删除(存在的key的value可以为空)。
        Integer aj7 = map.compute("aj7", (key, value) ->value == null ? null : value * 90 / 100);
        System.out.println("aj7打9折: " + aj7);
        System.out.println("打印map："+map);


        // computeIfAbsent的使用
        // 使用一：key不存在时，添加key-value映射对，key为null时，覆盖value值
        Map<String, Integer> map1 = new MyHashMap<>();
        map1.put("aj1", 1000);
        map1.put("aj2", 1500);
        map1.put("aj3", null);
        Integer aj2 = map1.computeIfAbsent("aj2", key -> 1600);
        System.out.println("aj2存在时，返回原value："+aj2);
        Integer aj3 = map1.computeIfAbsent("aj3", key -> 1700);
        System.out.println("aj3为空时，覆盖value值："+aj3);
        Integer aj4 = map1.computeIfAbsent("aj4", key -> 2000);
        System.out.println("aj4不存在时，添加value值："+aj4);
        System.out.println("打印map1："+map1);


        // 使用二：统计字符串出现个数
        Map<String, AtomicInteger> map2 = new MyHashMap<>();
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("2");
        list.add("4");
        list.add("5");
        list.add("1");
        list.forEach(str -> map2.computeIfAbsent(str, key -> new AtomicInteger()).incrementAndGet());
        System.out.println("打印map2："+map2);


        // computeIfPresent的使用
        // 如果key已经与某个值关联(或映射为null)，则可以使用该方法为指定的key计算映射值
        // + 如果此方法的映射函数返回null，则将删除该映射(前提，存在的key的value不为空2020-11-09)。
        // + 如果重新映射函数引发异常，则重新引发该异常，并且映射保持不变。
        // + 在计算过程中，不允许使用此方法修改此Map。

        Map<String, Integer> map3 = new MyHashMap<>();
        map3.put("aj5", 1000);
        map3.put("aj6", null);
        map3.put("aj9", 2000);


        // map不存在aj5
        Integer aj5 = map3.computeIfPresent("aj5", (key, value) -> value == null ? null : value * 90 / 100);
        System.out.println("aj5打9折: " + aj5);

        Integer aj6 = map3.computeIfPresent("aj6", (key, value) ->value == null ? null : value * 90 / 100);
        System.out.println("aj6打9折: " + aj6);

        Integer aj8 = map3.computeIfPresent("aj8", (key, value) -> value == null ? null : value * 90 / 100);
        System.out.println("aj8打9折: " + aj8);

        Integer aj9 = map3.computeIfPresent("aj9", (key, value) -> value != null ? null : value * 90 / 100);
        System.out.println("aj9打9折: " + aj9);

        System.out.println("打印map3："+map3);

    }


    /**
     * 二进制测试
     */
    public static void binaryTest() {

        System.out.println("255 : " + Integer.toBinaryString(255));
        System.out.println("256 : " + Integer.toBinaryString(256));

        System.out.println("5 : " + Integer.toBinaryString(5));
        int i1 = 5 >> 1;
        System.out.println("5>>1 : " + Integer.toBinaryString(i1));

        int i2 = 5 >>> 1;
        System.out.println("5>>>1 : " + Integer.toBinaryString(i2));
    }

    /**
     * https://blog.csdn.net/u010425839/article/details/106251923
     * <p>
     * 二进制或运算: 0|0=0 0|1=1 1|1=1，即只要有1结果就等于1.
     *
     * @param cap
     * @return
     */
    public static int tableSizeFor(int cap) {

        // step1：减1，是为了保证本身已经是2的n次幂的情形下(如:2^3=8)，直接返回该值，
        // 而不是返回另外的临近的大于它的其他2的n次幂的值(2^4=16)
        int n = cap - 1;
        // 全写
        n = n | n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        // step2：经过上述的无符号右移和或位运算的操作,会将最高位1后面的位全变为1

        // n < 0时，返回1；n >= MAXIMUM_CAPACITY，返回 MAXIMUM_CAPACITY；其他n + 1
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        //step3：此处的n+1结合step2 ,可以保证返回的是2的n次幂的数值
    }

}
